Flytdiagram eller sankeydiagram i R

ggalluvial survey R spørreundersøkelse ESS flytdiagram sankey

Denne posten beskriver hvordan man kan lage et flytdiagram også kalt sankeydiagram i R. Dette er en type diagrammer som viser hvordan individer eller grupper beveger seg mellom ulike statuser. Eksempelet er hvordan personer kan oppleve et parti som nærmeste parti, men ha stemt på et annet.

Øyvind Bugge Solheim https://www.oyvindsolheim.com (Institutt for samfunnsforskning)https://www.samfunnsforskning.no
2023-08-23

En type figurer jeg synes er ganske stilig og i tillegg gir en meningsfull framstilling av data er flytdiagrammer. De er nyttige når vi faktisk har bevegelse mellom ulike statuser og når vi vil forstå sammenhengen mellom ulike statuser. I R er det ganske enkelt å få til med ggplot og ggalluvial-pakka. Det er imidlertid ikke helt rett fram så jeg har skrevet en forklaring her.

Vi lager et plot som viser sammenhengen mellom hvilket parti man føler seg nærmest og hvilket parti man ville stemt hvis det var stortingsvalg i morgen.

knitr::opts_chunk$set(echo = TRUE,warning=FALSE,message=FALSE )

library(tidyverse)
library(survey)
library(srvyr)
library(haven)
#tabeller:
library(knitr)

Datasett

I dette eksempelet bruker jeg den siste runden av European Social Survey (runde 10) for Norge. Datafila er tilgjengelig på nettsida til European Social Survey

ess<- read_dta(here::here("_data/ESS/ESS10.dta"))

#Henter ut Norge:
ess_no <- ess %>% 
  filter(cntry=="NO")

Omkoder variabler

Det er nyttig å kode om variablene før vi setter i gang. Vi lager to nye variabler med mutate som heter stemte og naermeste. Jeg er litt forsiktig med å bruke æøå i R. Vi lager dem som faktorer med as_factor. Denne funksjonen gir nivåene navn etter label. Dermed slutter variablene å ha numeriske nivåer men heller lesbare nivåer som gir mening for oss, dvs. partinavnene. Jeg spesifiserer så rekkefølgen på nivåene i factoren med levels=. Dette sikrer at partiene kommer i “riktig” rekkefølge.

# rekkefølgen på partiene
partirekke <- c("Rødt","Sosialistisk Venstreparti","Arbeiderpartiet","Senterpartiet","Miljøpartiet De Grønne","Kristelig Folkeparti","Venstre","Høyre", "Fremskrittspartiet", "Kystpartiet", "Other", "Not applicable", "Refusal","Don't know","No answer")

#Lager faktorer med navnet på partiet som verdi
ess_no<- ess_no %>% 
  mutate(stemte=as_factor(prtvtbno),naermest=as_factor(prtclbno))

# Bruker partirekke til å flytte om på rekkefølgen til faktorene
ess_no<- ess_no %>% 
  mutate(stemte=factor(stemte,levels=partirekke),naermest=factor(naermest,levels=partirekke)) 

Gjør datasettet klart

For å lage en figur trenger vi å ha dataene i et langt format med bare antallet som hører til hver kombinasjon av stemte og naermeste. Dette får vi enkelt med group_by og n(). Vi laster også inn pakka ggalluvial som er en utvidelse av ggplot2 som gjør det mulig å lage flytdiagram.

library(ggalluvial)

#Lagrer:
ess_klar<- ess_no %>% 
#Gruppererer etter stemte og nærmeste:
  group_by(stemte,naermest) %>% 
#Regner ut antall for hver kombinasjon av verdiene på de to variablene:
  summarize(Antall=n())

# ser på toppen av det nye datasettet:
ess_klar %>%head() %>%   kable()
stemte naermest Antall
Rødt Rødt 16
Rødt Sosialistisk Venstreparti 8
Rødt Arbeiderpartiet 1
Rødt Miljøpartiet De Grønne 1
Rødt Other 1
Rødt Not applicable 9

Lager figur

Stratum

Vi har nå regnet ut antall av hver kombinasjon til figuren. Da trenger vi bare spesifisere hvilke variabler som hører til hvilken akse og hvilken som spesifiserer antallet. For å lage flytdiagrammer må vi først spesifisere ggplot. Så legget vi til geom_stratum. geom_stratum er søylene på hver side. Jeg spesifiserer fargen til svart slik at det blir mulig å skille mellom de ulike boksene og jeg gjør linja dobbelt så tjukk for at det blir ekstra tydelig.

ess_klar %>% 
#Når vi bruker ggplot2 må vi alltid kjøre ggplot først. 
#Inne i aes spesifiserer vi hvilke variabler vi vil ha:
  ggplot(aes(y = Antall,axis1 =naermest ,axis2 = stemte,fill=naermest))+
# geom stratum lager søylene:
  geom_stratum(color="black",size=2)

Alluvium

geom_alluvium spesifiserer så flytene som går mellom de to søylene. her sier vi at de skal være litt gjennomsiktig med alpha=.7. Nå nærmer vi oss den endelige figuren.

ess_klar %>% 
  ggplot(aes(y = Antall,axis1 =naermest ,axis2 = stemte,fill=naermest))+
  geom_stratum(color="black",size=2)+
# geom_alluvium lager flytene mellom søylene:
  geom_alluvium(alpha=.7)

Tekst

For at det skal være mulig å forstå figuren uten å nistirre på legenden legger vi til tekst på hver boks (stratum). Dette gjør vi med geom_text, men vi spesifiserer at det er stat="stratum" og at teksten (label) er after_stat(stratum). Dette siste er jeg litt usikker på hvorfor vi gjør, men det funker. Jeg har også spesifisert at color="black" selv om dette er unødvendig så lenge vi vil ha svart. Jeg gjør også teksten litt mindre med cex=3 fordi figuren ble litt mindre på nettsiden, men her er det bare å prøve seg litt fram.

ess_klar %>% 
  ggplot(aes(y = Antall,axis1 =naermest ,axis2 = stemte,fill=naermest))+
  geom_stratum(color="black",size=2)+
  geom_alluvium(alpha=.7)+
#geom_text legger på tekst på søylene
  geom_text(stat = "stratum", aes(label = after_stat(stratum)),color="black",cex=3)

Til slutt bruker jeg scale_x_continuous til å spesifisere navn. De to søylene står på 1 og 2 så jeg lager først breaks= og så labels= for disse to verdiene. I tillegg fjerner jeg legenden fordi denne ikke er nødvendig lenger etter at vi har lagt på tektst.

ess_klar %>% 
  ggplot(aes(y = Antall,axis1 =naermest ,axis2 = stemte,fill=naermest))+
  geom_stratum(color="black",size=2)+
  geom_alluvium(alpha=.7)+
  geom_text(stat = "stratum", aes(label = after_stat(stratum)),color="black",cex=3)+
# Her fjerner vi legend: 
  theme(legend.position="none")+
#Her lager vi labels på de x-aksen under de to søylene
  scale_x_continuous(breaks = c(1,2),labels = c("Nærmeste parti","Parti stemt"))

Konklusjon

Jeg må si jeg ble litt overrasket over hvor mange som ikke stemte på partiet de opplevde som nærmeste parti. Så kan det selvfølgelig være at nærmeste parti har endret seg i mellomtiden eller at man stemmer på andre partier av andre årsaker. For eksempel på grunn av saker som var spesielt viktige i den valgkampen eller på grunn av mer valgstrategiske hensyn. Om vi tar vekk de som ikke har svart på de to spørsmålene blir mønsteret litt enklere. Vi ser at det for det meste er partier på samme side av politikken der det er overganger, men det er også noen interessante bevegelser mellom for eksempel Senterpartiet og Fremskrittspartiet.

# unique(ess_klar$naermest)
ess_klar %>% 
#Fjerner rader som ikke er partier på de to variablene:
  filter(!grepl("Not ",naermest),!grepl("Refusal",naermest),!grepl("No ",naermest),!grepl("Other",naermest),!grepl("know",naermest),) %>% 
  filter(!grepl("Not ",stemte),!grepl("Refusal",stemte),!grepl("No ",stemte),!grepl("Other",stemte),!grepl("know",stemte),) %>% 
  ggplot(aes(y = Antall,axis1 =naermest ,axis2 = stemte,fill=naermest))+
  geom_stratum(color="black",size=2)+
  geom_alluvium(alpha=.7)+
  geom_text(stat = "stratum", aes(label = after_stat(stratum)),color="black",cex=3)+
   theme(legend.position="none")+
  scale_x_continuous(breaks = c(1,2),labels = c("Nærmeste parti","Parti stemt"))

Reuse

Text and figures are licensed under Creative Commons Attribution CC BY 4.0. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: "Figure from ...".

Citation

For attribution, please cite this work as

Solheim (2023, Aug. 23). Solheim: Flytdiagram eller sankeydiagram i R. Retrieved from https://www.oyvindsolheim.com/code/Flytdiagram i R/

BibTeX citation

@misc{solheim2023flytdiagram,
  author = {Solheim, Øyvind Bugge},
  title = {Solheim: Flytdiagram eller sankeydiagram i R},
  url = {https://www.oyvindsolheim.com/code/Flytdiagram i R/},
  year = {2023}
}